Skip to content

fix(packetrelay): add PacketListenerRelay idle deadlines#625

Merged
fortuna merged 5 commits into
mainfrom
fortuna/dnsintercept-unmap-local-resolver
Jun 17, 2026
Merged

fix(packetrelay): add PacketListenerRelay idle deadlines#625
fortuna merged 5 commits into
mainfrom
fortuna/dnsintercept-unmap-local-resolver

Conversation

@fortuna

@fortuna fortuna commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Give every PacketListenerRelay association a default 30s write-idle timeout using net.PacketConn deadlines.
  • Remove NewPacketRelayFromPacketListener constructor options; customize the timeout with PacketListenerRelay.SetWriteIdleTimeout.
  • Update the deprecated PacketListenerProxy adapter to use the native PacketListenerRelay timeout instead of wrapping with TimeoutPacketRelay.
  • Treat IPv4 and IPv4-mapped IPv6 addresses as equivalent when matching the DNS intercept local resolver.

Why

PacketListenerRelay associations need a timeout wherever they are used; otherwise dropped UDP packets can leave associations and goroutines alive indefinitely. Call sites were having to remember to wrap every PacketListenerRelay in TimeoutPacketRelay, which made this easy to miss.

The DNS intercept issue exposed another compatibility gap: some network stacks surface IPv4 UDP destinations in IPv4-mapped IPv6 form. Exact netip.AddrPort equality meant a configured resolver like 10.0.0.1:53 did not match [::ffff:10.0.0.1]:53, so DNS queries could fall through to the default relay and time out.

Testing

  • go test ./network/packetrelay
  • go test ./network
  • go test ./network/dnsintercept
  • go test ./...

@fortuna fortuna requested a review from ohnorobo June 16, 2026 05:54
@greptile-apps

greptile-apps Bot commented Jun 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR bakes a 30-second write-idle deadline directly into PacketListenerRelay associations so callers no longer need to manually wrap the relay with TimeoutPacketRelay. It also fixes a DNS intercept routing miss caused by IPv4-mapped IPv6 address comparisons.

  • PacketListenerRelay: a new shared packetListenerAssociation holds the net.PacketConn and deadline state; SendPacket calls SetDeadline(now+timeout) before every write, and ReceivePackets closes the association on any non-ErrShortBuffer error (including timeout).
  • DelegatePacketRelay: SetRelay is now void and accepts nil; a nil relay defers the failure to the next NewAssociation call via errNoRelay.
  • dnsintercept: destination matching now normalises both sides with Addr().Unmap() so [::ffff:10.0.0.1]:53 correctly matches a configured resolver of 10.0.0.1:53.

Confidence Score: 5/5

Safe to merge — the core deadline logic is well-tested and the IPv4-mapped address fix is isolated to a single helper function.

All changed paths have direct unit test coverage. The deadline mechanism uses standard net.PacketConn.SetDeadline semantics, the close-on-error path in ReceivePackets is exercised by TestPacketListenerRelayReceiveTimeoutClosesAssociation, and the IPv4-mapped fix is covered by the new TestDNSQueryRoutingWithIPv4MappedLocalResolver. The only open items are two stale doc comments on DelegatePacketRelay that do not affect runtime behaviour.

No files require special attention.

Important Files Changed

Filename Overview
network/packetrelay/packet_listener_relay.go Adds built-in write-idle deadline support via a new packetListenerAssociation shared between sender and receiver; deadline is refreshed on every SendPacket and the connection is closed when ReceivePackets exits. Logic is correct; mutex is properly acquired around close/refresh/get operations.
network/packetrelay/delegate_packet_relay.go Relaxes nil guard: SetRelay no longer returns an error, and NewDelegatePacketRelay silently accepts nil, deferring the failure to NewAssociation. Two doc comments still say "must not be nil" — misleading for interface consumers.
network/dnsintercept/packet_relay.go Adds isSameAddrPort helper that normalises IPv4-mapped IPv6 addresses via Addr.Unmap() before comparing, fixing DNS intercept miss when the OS surfaces IPv4 destinations in IPv4-mapped form.
network/packet_listener_proxy.go Deprecated adapter updated to pass the timeout directly to NewPacketRelayFromPacketListener instead of wrapping with TimeoutPacketRelay. Cleaner and correct; options are now applied before the relay is constructed.
network/packetrelay/packet_listener_relay_test.go New tests cover deadline refresh on NewAssociation and SendPacket, rejection of invalid timeouts, and verify that a timeout error from ReceivePackets closes the underlying connection.
network/dnsintercept/packet_relay_test.go New TestDNSQueryRoutingWithIPv4MappedLocalResolver test verifies that an IPv4-mapped destination ([::ffff:10.0.0.1]:53) is correctly routed to the DNS relay when the resolver is configured as plain IPv4.
network/packetrelay/delegate_packet_relay_test.go Tests updated to match the new void SetRelay signature and deferred-nil semantics; TestSetRelayWithNilValue now validates that nil initialisation succeeds but NewAssociation returns errNoRelay.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Caller
    participant PacketListenerRelay
    participant packetListenerAssociation
    participant net.PacketConn

    Caller->>PacketListenerRelay: NewAssociation()
    PacketListenerRelay->>net.PacketConn: ListenPacket()
    PacketListenerRelay->>packetListenerAssociation: create(conn, writeIdleTimeout)
    packetListenerAssociation->>net.PacketConn: SetDeadline(now + timeout)
    PacketListenerRelay-->>Caller: sender, receiver

    Caller->>+sender: SendPacket(p, dest)
    sender->>packetListenerAssociation: refreshDeadline()
    packetListenerAssociation->>net.PacketConn: SetDeadline(now + timeout)
    sender->>packetListenerAssociation: getPacketConn()
    sender->>net.PacketConn: WriteTo(p, dest)
    sender-->>-Caller: nil

    Note over packetListenerAssociation,net.PacketConn: If no SendPacket for writeIdleTimeout…
    net.PacketConn-->>receiver: ReadFrom → timeoutErr
    receiver->>packetListenerAssociation: close()
    packetListenerAssociation->>net.PacketConn: Close()
    receiver-->>Caller: timeoutErr
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Caller
    participant PacketListenerRelay
    participant packetListenerAssociation
    participant net.PacketConn

    Caller->>PacketListenerRelay: NewAssociation()
    PacketListenerRelay->>net.PacketConn: ListenPacket()
    PacketListenerRelay->>packetListenerAssociation: create(conn, writeIdleTimeout)
    packetListenerAssociation->>net.PacketConn: SetDeadline(now + timeout)
    PacketListenerRelay-->>Caller: sender, receiver

    Caller->>+sender: SendPacket(p, dest)
    sender->>packetListenerAssociation: refreshDeadline()
    packetListenerAssociation->>net.PacketConn: SetDeadline(now + timeout)
    sender->>packetListenerAssociation: getPacketConn()
    sender->>net.PacketConn: WriteTo(p, dest)
    sender-->>-Caller: nil

    Note over packetListenerAssociation,net.PacketConn: If no SendPacket for writeIdleTimeout…
    net.PacketConn-->>receiver: ReadFrom → timeoutErr
    receiver->>packetListenerAssociation: close()
    packetListenerAssociation->>net.PacketConn: Close()
    receiver-->>Caller: timeoutErr
Loading

Reviews (3): Last reviewed commit: "refactor(packetrelay): make writeIdleTim..." | Re-trigger Greptile

@fortuna fortuna changed the title fix(dnsintercept): match IPv4-mapped DNS resolver fix(packetrelay): add PacketListenerRelay idle deadlines Jun 16, 2026
@fortuna fortuna requested a review from jyyi1 June 16, 2026 06:24
Comment thread network/packetrelay/packet_listener_relay.go

@jyyi1 jyyi1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@fortuna fortuna enabled auto-merge (squash) June 17, 2026 21:23
@fortuna fortuna merged commit 342bf53 into main Jun 17, 2026
11 of 15 checks passed
@fortuna fortuna deleted the fortuna/dnsintercept-unmap-local-resolver branch June 17, 2026 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants